package com.duartepeixinho.P3D.Objects
{
	import com.duartepeixinho.P3D.Cameras.Camera;
	import com.duartepeixinho.P3D.Objects.Objects;
	import com.duartepeixinho.P3D.Core.Math.Matrix;
	import com.duartepeixinho.P3D.Core.Math.Vector3;
	import com.duartepeixinho.P3D.Scenes.Scene;

	/**
	 * P3D 
	 * @version 0.1
	 * @author Duarte Peixinho
	 */
	public class Object3D extends Objects
	{
		// objectlist
		private static var _OBJECTLIST:Array = new Array();
		
		// parent
		private var _parent:DisplayObject3D;
		
		// transformation matrix		
		protected var _transform:Matrix = new Matrix();
		protected var _lookAt:Matrix = new Matrix();
		
		protected var _position:Vector3 = new Vector3(0, 0, 0);
		
		protected var _angleX:Number = 0;
		protected var _angleY:Number = 0;
		protected var _angleZ:Number = 0;
		
		private var _scaleX:Number = 1;
		private var _scaleY:Number = 1;
		private var _scaleZ:Number = 1;
		
		public function Object3D(o:Object3D) 
		{
			_OBJECTLIST.push(o);
		}
		
		public function get getObjects():Array {
			return _OBJECTLIST;
		}
		
		/**
		 * Calculate Transformations 
		 * @param	p	Vector3
		 * @return		Vector3
		 */
		public function calcTransform(p:Vector3):Vector3 {								
			return _transform.transform(p);
		}
		
		/**
		 * UpdateMatrix
		 */
		public function updateMatrix(camera:Camera = null):void {
			_transform.identify();									
			
			//APPLY CAMERA TRANSFORMATION
			if (this is DisplayObject3D && camera) {
				_transform.multiplySelf(camera.transform);
			}
			
			// Translation
			var m:Matrix = new Matrix();
			m.translate(_position.x, _position.y, _position.z);
			
			// Rotation
			m.rotateX(_angleX);
			m.rotateY(_angleY);
			m.rotateZ(_angleZ);
			
			// Scale
			m.scale(_scaleX, _scaleY, _scaleZ);						
			
			if (_parent) {
				_parent.updateMatrix();
				_transform.multiplySelf(_parent.transform);
				_transform.multiplySelf(m);
				_parent.updateMatrix(camera);
			}
			else _transform.multiplySelf(m);
			
			// lookAt
			_transform.multiplySelf(_lookAt);
		}
		public function worldCoordinates():Vector3 {
			return _transform.transform(_position);
		}
		
		public function lookAt(target:Object3D):void {
			_lookAt.lookAt(this._position, target.position, new Vector3(0, 1, 0));
		}
		public function pitch(angle:Number):void {
			rotationX += angle;
		}
		public function yaw(angle:Number):void {
			rotationY += angle;
		}
		public function roll(angle:Number):void {
			rotationZ += angle;
		}		
		public function set rotationX(angle:Number):void {
			_angleX = angle * Math.PI / 180;			
		}
		public function set rotationY(angle:Number):void {
			_angleY = angle * Math.PI / 180;
		}
		public function set rotationZ(angle:Number):void {
			_angleZ = angle * Math.PI / 180;
		}
		public function get rotationX():Number {
			return _angleX * 180 / Math.PI;
		}
		public function get rotationY():Number {
			return _angleY * 180 / Math.PI;
		}
		public function get rotationZ():Number {
			return _angleZ * 180 / Math.PI;			
		}		
		public function set x(x:Number):void {
			_position.x = x;
		}
		public function set y(y:Number):void {
			_position.y = y;
		}
		public function set z(z:Number):void {
			_position.z = z;
		}
		public function get x():Number {
			return _position.x;			
		}
		public function get y():Number {
			return _position.y;
		}
		public function get z():Number {
			return _position.z;
		}	
		public function get position():Vector3 {
			return _position;
		}
		public function set position(position:Vector3):void {
			_position = position;
		}
		public function scaleX(scaleX:Number):void {
			_scaleX = scaleX;
		}
		public function scaleY(scaleY:Number):void {
			_scaleY = scaleY;
		}
		public function scaleZ(scaleZ:Number):void {
			_scaleZ = scaleZ;
		}				
		public function set scene(scene:Scene):void {
			_scene = scene;
		}
		public function get scene():Scene {
			return _scene;
		}
		public function set parent(parent:DisplayObject3D):void {
			_parent = parent;
		}
		public function get parent():DisplayObject3D {
			return _parent;
		}
		public function get transform():Matrix {
			return _transform;
		}

	}

}